- نظرة عامة
- ماذا يفعل البرنامج باختصار (للمبتدئ)
- هيكل المشروع (شجرة + وصف)
- متطلبات التشغيل
- خطوات التثبيت والتشغيل
- النشر على Render
- كيف يعمل التطبيق من المتصفح حتى قاعدة البيانات
- دليل الصفحات: كل ميزة وكيف تُحاكى
- شرح الوحدات التعليمية (تفصيل + مقتطفات + مصطلحات)
- قاعدة البيانات
- API Endpoints
- دليل التصميم
- ملاحظة أخلاقية وقانونية
- نتائج المشروع
- معجم مصطلحات بأمثلة عملية
- المراجع
EEHS (Educational Ethical Hacking Simulator) تطبيق ويب يشرح مراحل اختبار الاختراق بشكل محاكٍ داخل بيئة وهمية (بيانات ونتائج افتراضية) لربط الدرس النظري بما يحدث في المختبر الحقيقي (مثل Kali + Metasploitable داخل VirtualBox). الهدف التعليمي: فهم الاستطلاع، الهجوم، والحماية، وليس أداة فعلية للهجوم.
| مصطلح | بمعنى مبسّط | مثال مرتبط بـ EEHS |
|---|---|---|
| استطلاع (Reconnaissance) | جمع معلومات عن أهداف قبل الاستغلال | فحص Nmap يعرض منافذ من جدول sim_ports |
| استغلال (Exploitation) | استخدام ثغرة لتحقيق هدف (مثلاً جلسة) | محاكاة vsftpd في Metasploit |
| حماية | تخفيف الخطر: جدار، تعقيم، تشفير | Fail2Ban، htmlspecialchars، bcrypt |
إضافة توضيحية: البرنامج لا يرسل حزم شبكية ولا يتصل بعنوان 192.168.56.102 فعلياً. الرقم 192.168.56.102 رمز يشير إلى الضحية في التقرير، والنصوص في الطرفية مبنية من الدوال في modules/*_sim.py والجداول في eehs.db.
- تشغل الخادم بـ
python app.pyفيظهر الموقع علىhttp://127.0.0.1:5000. - الصفحة الرئيسية تقرأ أعداداً من جدول
attack_logsوتعرض آخر 10 سجلاً وبطاقات للوحدات الست. - كل وحدة لها صفحة HTML: أزرار تستدعي مسارات تبدأ بـ
/api/...ترجع JSON؛ المتصفح يعرض النتائج في صندوق يشبه الطرفية (terminal) بخط monospce. - قاعدة البيانات SQLite
eehs.dbتخزن المستخدمين الوهميين، المنافذ، التعليقات/الحمولات، وسجلاً لما يقوم به المتعلم داخل المحاكاة. - لا يوجد اختراق حقيقي: كل شيء داخل البرنامج وملفه المحلي.
| المسار | الوصف |
|---|---|
app.py |
تطبيق Flask: الصفحات ومسارات api — يجمع طلبات الواجهة ويستدعي دوال modules وdatabase |
database.py |
إنشاء eehs.db وتهيئة البيانات الافتراضية، ودالة log_attack لتسجيل الأحداث |
requirements.txt |
الحزم: Flask, Werkzeug, bcrypt, gunicorn (للإنتاج) |
render.yaml |
تعريف خدمة ويب Render (Blueprint) — gunicorn و$PORT |
eehs.db |
قاعدة SQLite (تُنشأ تلقائياً عند أول تشغيل) |
assets/css/style.css |
الألوان، الخطوط المحلية (TTF) |
assets/js/main.js |
دوال: apiPost, الطرفية، buildPortsTable، وغيرها — لإعادة استخدام نفس البرمجة في الصفحات |
assets/fonts/*.ttf |
IBM Plex Sans Arabic (موجودة محلياً) |
templates/*.html |
واجهات عربية: كل صفحة تمتد من base.html |
modules/*_sim.py |
منطق المحاكاة دون شيفرة هجوم حقيقي — القلب البرمجي لكل تمرين |
رابط static: في app.py يُعرَّف static_folder="assets" وstatic_url_path="/static" فالواجهة تستدعي الملفات مثل: /static/css/style.css (انظر url_for في base.html).
- Python 3.10+ (يُنصح بأحدث إصدار ثابت)
- pip لإدارة الحزم
- متصفح ويب حديث
# 1. الانتقال للمجلد
cd D:\VSCode\Projects\EEHS
# 2. تثبيت المتطلبات
pip install -r requirements.txt
# 3. تشغيل التطبيق
python app.py
# 4. فتح المتصفح على
# http://127.0.0.1:5000إن وُجدت قاعدة قديمة بغير الجداول المطلوبة، احذف الملف eehs.db ثم شغّل التطبيق من جديد ليُعاد إنشاؤها.
- ارفع المشروع إلى مستودع Git بحيث يكون مجلد المشروع (حيث
app.pyوrender.yaml) هو جذر المستودع، أو اضبط Root Directory في Render إلى ذلك المسار. - في Render: New → Blueprint (أو Web Service يدوياً) واربط المستودع.
- Blueprint يقرأ
render.yaml: بناءpip install -r requirements.txtثم تشغيلgunicorn app:app --bind 0.0.0.0:$PORT(المتغيرPORTيضبطه Render). - ملاحظة: ملف
eehs.dbعلى خطة Free Web يُحفَظ في نظام الملفات المؤقت للمثيل؛ عند إعادة نشر الخدمة أو إعادة إنشاء المثيل قد تُعاد تهيئة البيانات الافتراضية. لإبقاء دائم: قرص مرتبط (مدفوع) أو قاعدة بيانات إدارة (مثلاً PostgreSQL) لاحقاً. - محلياً:
python app.pyيستمع على0.0.0.0والمنفذ منPORT(افتراضي 5000). يمكن تعيينFLASK_DEBUG=1للتطوير. على Render التشغيل الفعلي عبرgunicornمنstartCommandوليسpython app.pyمباشرة.
- يدخل المستخدم صفحة (مثلاً
/nmap). خادم Flask ينفّذ دالةpage_nmapالتي تقرأsim_portsمرة لعرض جدول أولي في الصفحة. - يضغط «تشغيل الفحص». JavaScript ينفّذ
apiPost('/api/nmap/scan', { target_ip, scan_type })(منmain.js). الطلب POST يحمل JSON في الجسم. app.pyيستدعيsimulate_nmapمنmodules/nmap_sim.pyالتي:- تقرأ كل المنافذ من الجدول،
- تختار قائمة فرعية حسب النوع (فحص أساسي = سبعة منافذ شائعة؛ فحص إصدارات = اثنا عشر سطراً؛ فحص شامل = الكل + سطر OS وهمي)،
- تبني
output_linesمثل مخرجات Nmap.
- الرجوع JSON فيُعرض سطراً بسطر في
div#nmap-term(المحاكاة البصرية). - بعد فحص أو هجوم،
log_attackتُدخل سطراً فيattack_logsليظهر لاحقاً في لوحة التحكم. - نفس المسار يتكرر في وحدات أخرى:
POST→jsonify→ رسم نصوص في الطرفية.
مقتطف من app.py (تهيئة التطبيق ولوحة التحكم): يوضح كيف تُسحب الأعداد والأحدث من SQL:
# عند الاستيراد: init_db() تُنفّذ مرة
def _bootstrap():
init_db()
_bootstrap()
@app.route("/")
def index():
conn = get_db()
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM attack_logs")
total = cur.fetchone()[0]
# ... success / blocked / vuln_c ...
cur.execute(
"""
SELECT attack_type, target_ip, timestamp, result, success
FROM attack_logs ORDER BY id DESC LIMIT 10
"""
)
last = [dict(zip(["attack_type", "target_ip", "timestamp", "result", "success"], r)) for r in cur.fetchall()]
conn.close()
return render_template(
"index.html",
total_attacks=total,
success_attacks=ok,
blocked_attacks=blocked,
vuln_count=vuln_c,
last_attacks=last,
)الشرح: ORDER BY id DESC LIMIT 10 تعني آخر 10 سجلاً حسب التسلسل. الحقل success يساعد واجهة «ناجح / محجوب» على اللوحة.
| الصفحة | المسار | أهم ميزات واجهة | ما الذي يُحاكى؟ |
|---|---|---|---|
| لوحة التحكم | / |
أربع بطاقات أعداد، جدول آخر هجمات، 6 بطاقات وحدات | أعداد من attack_logs + sim_vulnerabilities |
| Nmap | /nmap |
IP، اختيار نوع فحص، زر فحص، طابور نصوص، جدول | قراءة sim_ports، توليد سطور nmap-شكل |
| Brute | /brute-force |
نام مستخدم، هدف نصي ثابت، طرفية، 4 حماية + اختبار | قائمة كلمات وهمية، نجاح msfadmin أو حظر إذا protected |
| XSS | /xss |
صندوق DVWA، تعقيم، تعليقات، سرقة كوكي نصي | check_xss + sanitize_input + جدول xss_payloads |
| تشويه | /defacement |
معاينة HTML، اختيار ملف، تقييد امتداد | simulate_upload / apply_protection + upload_attempts |
| نص صريح | /cleartext |
رقائق أوامر MySQL، جدول مقارنة، زر bcrypt | get_cleartext_users + فلتر md5_hex + get_hashed_users |
| Metasploit | /metasploit |
banner، رقائق أوامر، exploit، حماية ثلاثية | simulate_metasploit + protected |
| حول | /about |
جدول بيانات المشروع + تنبيه أخلاقي | ثابت في القالب |
| واجهة برمجة | /api/... |
JSON فقط (لا واجهة) | يرتبط بكل الأعلى |
ملاحظة: صفحات about وindex لا تُنفّذ «هجوماً» — تعرض بياناتاً أو وصفاً.
- المفهوم: معرفة المنافذ المفتوحة والخدمات يقلل المجهول ويخبرك أين تبحث لاحقاً.
- كيف في الواقع؟ أداة Nmap ترسل حزماً وتحلل الردود. هنا: النتائج قادمة من جدول
sim_portsوتُبنى نصوص تشبه مخرجات Nmap. - دالة رئيسية في المشروع:
simulate_nmap(scan_type, target_ip)فيmodules/nmap_sim.py— تُرجعoutput_linesوportsوos_guess. - حماية: جدار (محاكاة) عبر
POST /api/nmap/protectيُسجّل سطراً فيattack_logsويُرجع قائمة منافذ مُغلقة وهمية.
| مصطلح | تعريف | مثال |
|---|---|---|
| منفذ (Port) | رقم يربط تطبيقاً بخدمة على IP | 80/HTTP |
| الخدمة (Service) | البرنامج المستمع (Apache, ssh…) | Apache 2.2.8 |
| -sV | فحص إصدارات (في nmap الحقيقي) | في المحاكاة يُقارن بعرض 12 سطراً من المنافذ |
| -A -T4 | تجميع (إصدارات + OS) مع سرعة (في nmap) | في المحاكاة: كل المنافذ + سطر OS details وهمي |
كيف تختار النتائج الداخلية؟ الجزء التالي من الكود (مختصر) يوضح: الفحص «الأساسي» يعيد قائمة مفلترة من عناوين شائعة؛ «الإصدارات» يأخذ 12 مرفقاً أولى؛ «الشامل» يأخذ الكل (مع محاكاة OS في النصوص).
# من modules/nmap_sim.py
st = str(scan_type)
if st in ("basic", "فحص أساسي"):
show = [p for p in ports_out if p["port"] in (21, 22, 23, 80, 443, 3306, 445)]
elif st in ("sv", "فحص إصدارات", "-sV"):
show = ports_out[:12]
else:
show = ports_out
# ثم تُركّب كل سطر من show في سطور مثل: 21/tcp open ftp vsftpd 2.3.4وظيفة firewall_closed_ports: تُرجع قائمة أرقام (محاكاة) لعرض «ما أُغلق» دون تعديل أي جدول فعلي — الهدف تعليمي (إدراك سطح الهجوم).
- المفهوم: جرب عدة كلمات مرور تلقائياً — خطر قفل الحساب وسجلات وحظر IP — والحلول: Fail2Ban، كلمات قوية، 2FA، حد أقصى للمحاولات.
- في المشروع:
simulate_brute_forceتُرجع محاولات وهمية؛ عندprotected=Trueتظهر رسالة حظر بعد 3 فشل. - حماية: Fail2Ban، كلمة قوية، 2FA، قفل بعد محاولات — مُوضحة كواجهة تفاعلية (مخرجات وهمية).
| الدالة | المعاملات | المُرجع | وصف |
|---|---|---|---|
simulate_brute_force |
username, target, protected |
attempts, success, password |
حركة وهمية لسجل Hydra — target يُسجّل فقط ولا يُتصل به |
مقتطف من modules/brute_force_sim.py: منطق «مع حماية» و«بدون»:
def simulate_brute_force(username, target, protected=False):
dict_words = ["password", "123456", "qwerty", "letmein", "admin", "msfadmin"]
if protected:
for w in dict_words[:3]:
attempts.append({"line": f"[ATTEMPT] {username}:{w} → FAILED", "ok": False})
attempts.append({"line": "[BLOCKED] IP حُظر بعد 3 محاولات فاشلة", "blocked": True, ...})
return { "success": False, ... }
for w in dict_words:
if w != "msfadmin":
attempts.append({"line": f"[ATTEMPT] {username}:{w} → FAILED", "ok": False})
attempts.append({"line": f"[SUCCESS] login: {username} password: msfadmin", "ok": True})
return { "success": True, "password": "msfadmin", ... }للمبتدئ: password الظاهر في «النجاح» ثابت في المحاكاة ولا يعني أن أي خادم SSH حقيقي يقبل msfadmin — فقط يعلمك شكل سطر نجاح Hydra.
- المفهوم: حقن سكربت/وسوم تُنفّذ في متصفح الضحية — الحل: تعقيم المخرجات، CSP، وعلى الأقل HttpOnly للكوكي.
- في المشروع:
check_xssيفحص أنماطاً شائعة بـregex؛sanitize_inputيستبدل&و<و>وعلامات الاقتباس — نفس فكرةhtmlspecialcharsفي PHP. عند تفعيل «الحماية» في الصفحة، المخرج نص لا يُفسَّر HTML. - مخزن: يُحفَظ في
xss_payloadsعندما يكونpayload_typeيساويمخزن(أوstoredمُعادلة في الطلب) ويُستعاد بـGET /api/xss/stored.
| مصطلح | تعريف | مثال |
|---|---|---|
| Reflected (ينعكس) | المدخلات تُرجع في نفس الرد فوراً | ?name=... |
| DOM | تغيير الصفحة بـ JavaScript دون الاعتماد فقط على خادم | معالجات أحداث في المتصفح |
| CSP | تعليمات للمتصفح: من أين يسمح بتحميل سكربت/صور | default-src 'self' في المحاكاة |
| HttpOnly | يمنع document.cookie من رؤية الكوكي (من JavaScript) |
يساعد لكن لا يكفي لوحده لكل XSS |
مقتطف من modules/xss_sim.py (بداية check_xss):
patterns = [
(r"(?i)<\s*script", "Script tag", "عالي", "مُعكوس/مخزن"),
(r"(?i)on\w+\s*=", "معالج حدث (onerror...)", "عالي", "DOM/Reflected"),
# ...
]
for reg, name, sev, typ in patterns:
m = re.search(reg, p)
if m:
return { "is_xss": True, "pattern_found": m.group(0)[:80], ... }شرح مبسّط: re.search يبحث عن شكل في النص. المحاكاة ليست كاشف 100% لكل الاختراقات في العالم — بل نموذج تعليمي.
- المفهوم: رفع ملف يسمح بتنفيذ أوامر (مثلاً
.php) على خادم ويب — ثم تغيير الصفحة الرئيسية. الحماية: فلتر امتدادات،AddType، تعطيل محرك PHP في موقع معين. - في المشروع:
simulate_uploadوapply_protection— القرارallowedيعتمد على الامتداد ومفعّل التقييد؛ الجدولupload_attemptsيسجّل المحاولة. - الامتدادات: المخاطرة:
php… | المسموح عند التقييد:jpg/png/gif. - حماية: نص
apply_protectionيُظهر مثال.htaccessتعليمي (في الواجهة وفي JSON عندPOST /api/defacement/protect).
فكرة منطق (من defacement_sim.py باختصار): إن كان التقييد مفعّلاً وامتداد الملف ليس في القائمة البيضاء → رفض؛ وإن كان php وبدون حماية → تُرجع exec_output بسلسلة تحاكي id وHACKED.
- المفهوم: تخزين
passwordكنص يسمح لمن يهرب قاعدة البيانات بالدخول مباشرة؛bcryptيُبطئ التخمين ويحتاج أدوات ثقيلة، خاصة عندcostمناسب. - في المشروع:
get_cleartext_users/get_hashed_usersمنsim_users؛ في الجدول يُظهر عمود MD5 عبر فلترmd5_hex(قيم مقصوصة لعرض الضعف — MD5 لا يُنصح به لتخزين كلمات مرور اليوم)؛password_hashbcrypt حقيقي مُخزّن.
# من app.py — عرض تعليمي فقط: مقارنة بصمات
@app.template_filter("md5_hex")
def _md5_hex(s):
return hashlib.md5(s.encode("utf-8")).hexdigest()[:10] + "…"- كود فكري في القالب (PHP):
password_hash/password_verifyكما في صفحةcleartext.html.
| مصطلح | تعريف | مثال |
|---|---|---|
| Rainbow table | جدول: hash → نصوص شائعة لتسريع «البحث» | يساعد كسر MD5 السريع |
| بذرة (Salt) + تكلفة (cost) | يزيدان تفرّد الـ hash ويُبطئان التخمين | bcrypt في password_hash |
| KDF آمن (باختصار) | وظيفة مقصودة أن تكون بطيئة | bcrypt/argon2 |
- المفهوم: اختيار استغلال (exploit) + خيارات (مثل
RHOSTSالهدف) + تشغيل → في النظام الحقيقي: جلسةmeterpreterأو shell. - في المشروع:
simulate_metasploit— عندprotected=Falseتُرجعsession_open: Trueوسطوح بـidوrootنص؛ عندprotected=Trueفشل اتصال (محاكاة تعليمية). - Chips في الصفحة تولّد سطور تشبه msfconsole (أمر
useوset RHOSTS…).
فكرة من metasploit_sim.py (جزء إيجابي): إن لم يُحمَِ الهدف → سطور بانر، محاولة، Connected to backdoor، session 1، وما يشبه أوامر id / whoami — كلها نص يُرسل للواجهة.
الجداول: attack_logs, sim_users, sim_ports, sim_vulnerabilities, xss_payloads, upload_attempts — حسب database.py.
- مستخدمون (10): بيانات افتتاحية +
bcryptلكلpassword_hashعبرhash_bcryptفيinit_db— الحقلpassword_plainللدرس على خطر التخزين النصي. - منافذ (20) وثغرات (10): كما في مواصفات المشروع — تُطابق فكرياً بيئات مثل Metasploitable (أسماء خدمات وإصدارات قديمة عمداً).
- سجلات هجوم (15): داخل
init_dbلآخر 30 يوماً تقريباً — تشغل أولاً لوحة التحكم حتى بدون تفاعل. - سجلات جديدة: تُضاف عند استدعاء
log_attackمنapp.pyبعد فحوصات/هجمات محاكاة.
مقتطف من log_attack (فكرة الحفظ): يدخل attack_type وtarget_ip وresult وsuccess (1=من منظور «نجاح المحاكاة/الوصف» حسب المسار) وdetails_json اختياري.
cur.execute(
"""
INSERT INTO attack_logs
(attack_type, target_ip, timestamp, result, details_json, success)
VALUES (?, ?, ?, ?, ?, ?)
""",
(attack_type, target_ip, now, result, details_json, 1 if success else 0),
)| طريقة | المسار | وصف | مثال مُرجع (جزئي) |
|---|---|---|---|
| GET | / |
لوحة التحكم | HTML |
| GET | /nmap |
صفحة Nmap | — |
| POST | /api/nmap/scan |
فحص وهمي | {"output_lines":[], "ports":[]} |
| POST | /api/nmap/protect |
جدار ناري (محاكاة) | {"closed_ports":[]} |
| POST | /api/brute-force/attack |
Brute + حماية | {"success": true/false, "attempts":[]} |
| GET/POST | /xss و /api/xss/* |
حقن، تعقيم، مخزن | {"check":{}, "sanitize":{}} |
| GET | /api/xss/stored |
تعليقات | {"items":[]} |
| POST | /api/defacement/upload |
رفع (JSON اسم/امتداد) | {"allowed", "exec_output"} |
| POST | /api/defacement/protect |
.htaccess | {"htaccess_content"} |
| POST | /api/cleartext/query |
أوامر MySQL وهمية | {"output"} + users عند SELECT |
| POST | /api/cleartext/hash |
وضع bcrypt | {"users":[]} |
| POST | /api/metasploit/exploit |
استغلال | {"output_lines":[]} |
| GET | /api/stats |
أرقام لوحة | {"total_attacks",...} |
للمبتدئ عند اختبار API يدوياً: يُفضّل Postman أو تبويب «Network» في المتصفح لرؤية نفس الطلبات التي ترسلها الصفحات (طريقة POST ورأس Content-Type: application/json).
- الخط: IBM Plex Sans Arabic من
assets/fonts(ملفات .TTF محلية) عبرformat('truetype')فيstyle.css. - الألوان: متغيرات CSS كما في الجذر (
--bg-primary,--green…) — يسهل تغيير السِمة دون تعديل كل الصفحات. - الأزرار:
border-radius: 8px،padding: 8px 18pxكحد. - البطاقات:
12px، حد1px solid #30363d، بدون شريط جانبي ديكوري. - اتجاه:
rtlعلىhtmlوbody— النصوص من اليمين؛ الطرفيةltrفالأوامر إنجليزية مثل nmap. - حركة: انتقال
200msفقط (hover) — تقليل التشويت البصري ليركز المتعلم على المحتوى.
من main.js (أدوات مشتركة): apiPost يرسل JSON؛ appendToTerminal يضيف div داخل وعاء الطرفية ويُحريك التمرير للأسفل — هذا يمنح إحساس كتابة سطر دون تثبيت حزم طرفية في النظام.
async function apiPost(url, data) {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return await res.json();
}يقتصر الاستخدام على التدريب والبيئات المصرّح بها أو المعزولة. الدخول غير المصرح به لأنظمة حقيقية جريمة في أغلب التشريعات. EEHS لا ينفّذ هجمات حقيقية ولا يستهدف عناوين خارجة عن المحاكاة.
- واجهة عربية موحّدة ولوحة إحصاء من
attack_logs. - ست وحدات تربط نظرية + محاكاة + حماية لكل سيناريو.
- قاعدة بيانات تُظهر مخاطر التخزين الصريح وقوة
bcryptفي سياق تعليمي.
| مصطلح | ماذا يعني ببساطة؟ | مثال «من الحياة» / من EEHS |
|---|---|---|
| JSON | تنسيق نصي لتبادل بيانات بين الخادم والمتصفح | الرد من /api/nmap/scan هو JSON |
| الـ API | واجهة program تتكلم بها أنت أو الواجهة | كل مسار يبدأ بـ /api/ |
| SQLite | قاعدة بيانات في ملف واحد | eehs.db بجانب المشروع |
| Flask | إطار Python لبناء خادم ويب + مسارات | app = Flask(__name__) |
| Regex (تعبير نمطي) | وصف شكل نص (مثلاً “يبدأ بـ <”) |
check_xss يفحص <script |
| Hash (بصمة) | مخرجات دالة غير عكسيّة بسهولة من النص | MD5/SHA لشرح الضعف — bcrypt للتخزين الجيد |
| CWE/CVE | تصنيف ضعف / رقم مُعرّف لثغرة مُوثّقة | sim_vulnerabilities تذكر CVE-... |
| Shell / Terminal | واجهة سطر أوامر | div.terminal تشبه الشاشة سوداء/خضراء فقط عرضياً |
تذكير: الفصل بين ما يفعله المشروع (نص + قاعدة) وما يفعله المختبر الحقيقي (Kali, Metasploitable) يبني فهماً صحيحاً ويقلل الأخطاء الأخلاقية.
- Nmap — دليل الاستخدام الرسمي (nmap.org).
- OWASP — XSS ومعالجة المدخلات.
- CVE-2011-2523 — vsftpd 2.3.4 (للسياق التاريخي).
- Metasploit Unleashed — مقدمة تعليمية.
- PCI-DSS — مبدأ تخزين بيانات اعتماد آمن.
- RFC 5246/8446 (TLS) — فهم لماذا النص الصريح يُعرّض الاعتمادات.
- CWE-79 (XSS) — تصنيف الضعف.
- VirtualBox — توثيق الشبكات المعزولة (Host-Only) للمختبرات.
جامعة بيشة — قسم الأمن السيبراني — 2025-2026